/**
 * @constructor Creates a new memory manager for the provided array.
 * @param {memory} An array to use as the backing memory.
 */
function MemoryManager(memory) {
    this.mem = memory;
    this.index = {}
}

/**
 * Allocates a block of memory of requested size.
 * @param {number} size - The size of the block to allocate.
 * @returns {number} A pointer which is the index of the first location in the allocated block.
 * @throws If it is not possible to allocate a block of the requested size.
 */
MemoryManager.prototype.allocate = function(size) {
    var pointer = -1;
    for (var i = 0; i < this.mem.length; i++) {
        if (this.mem[i] === undefined) {
            if ((this.mem.slice(i, i + size)).length === size && (this.mem.slice(i, i + size).filter(v => v != undefined) || []).length === 0) { pointer = i; break; }
        }
    }
    if (pointer === -1 || size > this.mem.length) throw 'allocate error', 'no enough space to allocate';
    for (var i = pointer; i < pointer + size; i++) this.mem[i] = '';
    this.index[pointer] = size;
    return pointer;
};

/**
 * Releases a previously allocated block of memory.
 * @param {number} pointer - The pointer to the block to release.
 * @throws If the pointer does not point to an allocated block.
 */
MemoryManager.prototype.release = function(pointer) {
    if (pointer < 0 || pointer >= this.mem.length || this.mem[pointer] === undefined)
        throw 'release error', 'release a unallocated block or not exist block';
    var release_size = this.index[pointer]
    for (var i = pointer; i < pointer + release_size; i++) this.mem[i] = undefined;
};

/**
 * Reads the value at the location identified by pointer
 * @param {number} pointer - The location to read.
 * @returns {number} The value at that location.
 * @throws If pointer is in unallocated memory.
 */
MemoryManager.prototype.read = function(pointer) {
    if (pointer >= this.mem.length || pointer < 0) throw 'read memory error', 'index out of range';
    if (this.mem[pointer] === undefined) throw 'read memory error', 'try to read from unallocated memory';
    return this.mem[pointer] === '' ? undefined : this.mem[pointer]
}

/**
 * Writes a value to the location identified by pointer
 * @param {number} pointer - The location to write to.
 * @param {number} value - The value to write.
 * @throws If pointer is in unallocated memory.
 */
MemoryManager.prototype.write = function(pointer, value) {
    if (pointer >= this.mem.length || pointer < 0) throw 'write memory error', 'index out of range';
    if (this.mem[pointer] === undefined) throw 'write memory error', 'try to write to unallocated memory';
    this.mem[pointer] = value;
}
var mem = new MemoryManager(new Array(256));
mem.allocate(512);